package com.fsy.weibao.workorder.service.impl;

import cc.mrbird.febs.common.authentication.JWTUtil;
import cc.mrbird.febs.common.domain.QueryRequest;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.common.service.CacheService;
import cc.mrbird.febs.common.utils.SortUtil;
import cc.mrbird.febs.system.domain.User;
import cc.mrbird.febs.system.service.UserService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fsy.weibao.workorder.dao.WorkOrderMapper;
import com.fsy.weibao.workorder.domain.ProcessHistory;
import com.fsy.weibao.workorder.domain.WorkOrder;
import com.fsy.weibao.workorder.service.WorkOrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.flowable.engine.*;
import org.flowable.engine.common.api.delegate.event.FlowableEngineEventType;
import org.flowable.engine.common.api.delegate.event.FlowableEvent;
import org.flowable.engine.common.api.delegate.event.FlowableEventListener;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.*;

@Slf4j
@Service("workOrderService")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class WorkOrderServiceImpl
        extends ServiceImpl<WorkOrderMapper, WorkOrder>
        implements WorkOrderService, FlowableEventListener {

    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ProcessEngine processEngine;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private CacheService cacheService;
    @Autowired
    private UserService userService;

    @PostConstruct
    public void init() {
        runtimeService.addEventListener(this,
                FlowableEngineEventType.PROCESS_COMPLETED,
                FlowableEngineEventType.TASK_CREATED);
    }

    @Override
    @Transactional
    public void add(WorkOrder order) throws Exception {
        ProcessInstance process = runtimeService.startProcessInstanceByKey("weibaoProcess");

        //创建人为当前登录用户
        String token = (String) SecurityUtils.getSubject().getPrincipal();
        User user = cacheService.getUser(JWTUtil.getUsername(token));
        order.setCreateUser(user.getUserId());
        order.setCurUser(user.getUserId());
        order.setCreateTime(new Date());
        order.setStatus(WorkOrder.STATUS_DISTRIBUTE);
        order.setProcessId(process.getProcessInstanceId());
        save(order);
    }

    @Override
    public void update(WorkOrder order) {
        log.info("update work order {}", order);
        baseMapper.updateById(order);
    }

    @Override
    @Transactional
    public void handle(WorkOrder req) throws Exception {
        WorkOrder realOrder = baseMapper.selectById(req.getId());
        if( realOrder == null ) {
            throw new FebsException("任务不存在");
        }

        //流程里没有待执行的task表示流程已经结束，不能再执行了
        Task task = taskService.createTaskQuery().processInstanceId(realOrder.getProcessId()).singleResult();
        if( task == null ) {
            throw new FebsException("任务已结束");
        }

        //当前登录用户
        String token = (String) SecurityUtils.getSubject().getPrincipal();
        User loginUser = cacheService.getUser(JWTUtil.getUsername(token));

        /**
         * 根据流程处于不同的节点，决定不同的处理方式
         */
        Map<String, Object> variables = new HashMap<>();
        if( task.getTaskDefinitionKey().equals("dispatchTask")) {
            //在派单阶段：
            //根据派单方式设置broad变量到流程
            //根据是否设置了审核人，设置needApprove到流程
            if( req.getDistributeType() == null ) {
                throw new FebsException("必须指定派单方式");
            }
            if( req.getDistributeType() == 0 ) {
                realOrder.setCurUser(req.getHandleUser());
                variables.put("broad", false);
            }
            else {
                realOrder.setCurUser(null);
                variables.put("broad", true);
            }

            //设置审核人
            Long acceptUserId = req.getAcceptUser();
            if( acceptUserId == -1 ) {
                acceptUserId = null;
            }
            realOrder.setAcceptUser(acceptUserId);
            variables.put("needApprove", acceptUserId != null);
        }
        else if( task.getTaskDefinitionKey().equals("grabTask")) {
            //抢单阶段
            //将当前登录用户设置为工单的当前用户，即被他抢到了
            realOrder.setCurUser(loginUser.getUserId());
        }
        else if( task.getTaskDefinitionKey().equals("handlingTask")) {
            //处理阶段
        }
        else if( task.getTaskDefinitionKey().equals("approveTask")) {
            //审核阶段
            //根据审核是否通过，设置accept变量到流程
            variables.put("accept", req.getAccept());
            taskService.addComment(task.getId(), realOrder.getProcessId(),
                    "result", req.getAccept() ? "审核通过" : "审核不通过");
        }

        if( req.getRemark() != null ) {
            taskService.addComment(task.getId(), realOrder.getProcessId(), req.getRemark());
            //taskService.addComment(task.getId(), realOrder.getProcessId(), "remark", req.getRemark());
        }

        baseMapper.updateById(realOrder);
        //设置节点处理人员
        taskService.setOwner(task.getId(), loginUser.getUserId().toString());
        taskService.complete(task.getId(), variables);
    }

    @Override
    public WorkOrder getWorkOrderById(int id) {
        return baseMapper.selectOne(new LambdaQueryWrapper<WorkOrder>().eq(WorkOrder::getId, id));
    }

    @Override
    public WorkOrder getWorkOrderByProcess(String processId) {
        return baseMapper.selectOne(new LambdaQueryWrapper<WorkOrder>().eq(WorkOrder::getProcessId, processId));
    }

    @Override
    public IPage<WorkOrder> findWorkOrders(WorkOrder order, QueryRequest request) {
        try {
//            QueryWrapper<WorkOrder> queryWrapper = new QueryWrapper<>();
//
//            if (order.getType() != null ) {
//                queryWrapper.lambda().eq(WorkOrder::getType, order.getType());
//            }
//            if (order.getStatus() != null ) {
//                queryWrapper.lambda().eq(WorkOrder::getStatus, order.getStatus());
//            }
//            if (StringUtils.isNotBlank(order.getName())) {
//                queryWrapper.lambda().like(WorkOrder::getName, order.getName());
//            }
//            if (StringUtils.isNotBlank(order.getProject())) {
//                queryWrapper.lambda().like(WorkOrder::getProject, order.getProject());
//            }
//
//            Page<WorkOrder> page = new Page<>(request.getPageNum(), request.getPageSize());
//            SortUtil.handlePageSort(request, page, "createTime", FebsConstant.ORDER_DESC, true);
//
//            return this.page(page, queryWrapper);
            Page<User> page = new Page<>();
            SortUtil.handlePageSort(request, page);
            return baseMapper.findWorkOrders(page, order);
        } catch (Exception e) {
            log.error("获取维保任务失败", e);
            return null;
        }
    }

    /**
     * 获取任务工单的流程记录
     * @param workOrderId
     * @return
     */
    @Override
    public List<ProcessHistory> getProcessHistory(int workOrderId) {
        WorkOrder order = getWorkOrderById(workOrderId);
        if( order == null ) {
            return null;
        }
        List<ProcessHistory> histories = new ArrayList<>();
        ProcessHistory history = new ProcessHistory();
        history.setTaskName("创建");
        history.setCompleteTime(order.getCreateTime());
        User user = userService.getById(order.getCreateUser());
        if( user != null ) {
            history.setUserName(user.getUsername());
            history.setUserAvatar(user.getAvatar());
        }
        histories.add(history);

        List<HistoricTaskInstance> tasks =
                historyService.createHistoricTaskInstanceQuery().processInstanceId(order.getProcessId()).orderByTaskCreateTime().asc().list();
        for( HistoricTaskInstance task : tasks ) {
            history = new ProcessHistory();
            List<Comment> comments = taskService.getTaskComments(task.getId(), "result");
            if( comments!=null && comments.size()>0 ) {
                history.setTaskName(comments.get(0).getFullMessage());
            }
            else {
                history.setTaskName(task.getName());
            }
            history.setCompleteTime(task.getEndTime());
            user = userService.getById(task.getOwner());
            if( user != null ) {
                history.setUserName(user.getUsername());
                history.setUserAvatar(user.getAvatar());
            }
            comments = taskService.getTaskComments(task.getId());
            if( comments!=null && comments.size()>0 ) {
                history.setRemark(comments.get(0).getFullMessage());
            }
            histories.add(history);
        }

        return histories;
    }

    /**
     * Flowable事件处理
     * @param flowableEvent
     */
    @Override
    public void onEvent(FlowableEvent flowableEvent) {

        if( flowableEvent.getType() == FlowableEngineEventType.TASK_CREATED ) {
            onTaskCreate((org.flowable.engine.common.impl.event.FlowableEntityEventImpl) flowableEvent);
        }
        else if( flowableEvent.getType() == FlowableEngineEventType.PROCESS_COMPLETED ) {
            onProcessComplete((org.flowable.engine.delegate.event.impl.FlowableEntityEventImpl) flowableEvent);
        }
    }

    @Override
    public boolean isFailOnException() {
        return false;
    }

    @Override
    public boolean isFireOnTransactionLifecycleEvent() {
        return false;
    }

    @Override
    public String getOnTransaction() {
        return null;
    }

    /**
     * 流程节点开始
     * !!!注意!!! FlowableEntityEventImpl对于task和process是不一样的实现（包不一样），所以用全包路径
     * @param event
     */
    private void onTaskCreate(@org.jetbrains.annotations.NotNull org.flowable.engine.common.impl.event.FlowableEntityEventImpl event) {
        String procId = event.getProcessInstanceId();
        WorkOrder workOrder = getWorkOrderByProcess(procId);
        if( workOrder == null ) {
            return;
        }

        //根据当前流程节点更新任务工单的状态
        TaskEntity taskEntity = (TaskEntity) event.getEntity();
        String taskKey = taskEntity.getTaskDefinitionKey();
        switch(taskKey) {
            case "dispatchTask":
                workOrder.setStatus(WorkOrder.STATUS_DISTRIBUTE);
                break;
            case "grabTask":
                workOrder.setStatus(WorkOrder.STATUS_GRAB);
                break;
            case "preHandleTask":
                workOrder.setStatus(WorkOrder.STATUS_PRE_HANDLE);
                break;
            case "handlingTask":
                workOrder.setStatus(WorkOrder.STATUS_HANDLING);
                break;
            case "approveTask":

                workOrder.setStatus(WorkOrder.STATUS_APPROVAL);
                break;
        }

        update(workOrder);
    }

    /**
     * 整个流程结束
     * @param event
     */
    private void onProcessComplete(org.flowable.engine.delegate.event.impl.FlowableEntityEventImpl event) {
        String procId = event.getProcessInstanceId();
        WorkOrder workOrder = getWorkOrderByProcess(procId);
        if( workOrder == null ) {
            return;
        }
        workOrder.setStatus(WorkOrder.STATUS_COMPLETE);
        update(workOrder);
    }
}
